package com.music.glide.load.engine.bitmap_recycle

import android.graphics.Bitmap
import com.music.glide.util.Util

/**
 * 利用 Bitmap.reconfigure(int, int, Bitmap.Config)
 * 来重用位图是一种提高 Android 内存使用效率的策略
 */

class KSizeStrategy : KLruPoolStrategy {

    private val keyPool by lazy { KeyPool() }

    private val groupMap by lazy { KGroupLinkedMap<Key, Bitmap>() }

    private val sortedSizes by lazy { KPrettyPrintTreeMap<Int, Int>() }

    override fun put(bitmap: Bitmap) {
        val size = Util.getBitmapByteSize(bitmap)
        val key = keyPool.get(size)
        groupMap.put(key, bitmap)
        val current = sortedSizes[size]
        sortedSizes[size] = if (current == null) 1 else current + 1
    }

    override fun get(width: Int, height: Int, config: Bitmap.Config): Bitmap? {
        val size = Util.getBitmapByteSize(width, height, config)
        var key = keyPool.get(size)
        val possibleSize = sortedSizes.ceilingKey(size)
        if (possibleSize != null && possibleSize != size && possibleSize <= size * MAX_SIZE_MULTIPLE) {
            keyPool.offer(key)
            key = keyPool.get(size)
        }
        val result = groupMap.get(key)
        if (result != null) {
            result.reconfigure(width, height, config)
            if (possibleSize != null) {
                decrementBitmapOfSize(possibleSize)
            }
        }
        return result
    }

    override fun removeLast(): Bitmap? {
        val removed = groupMap.removeLast()
        if (removed != null) {
            decrementBitmapOfSize(Util.getBitmapByteSize(removed))
        }
        return removed
    }

    override fun logBitmap(bitmap: Bitmap): String {
        return getBitmapString(bitmap)
    }

    override fun logBitmap(width: Int, height: Int, config: Bitmap.Config?): String {
        return getBitmapString(Util.getBitmapByteSize(width, height, config))
    }

    override fun getSize(bitmap: Bitmap): Int {
        return Util.getBitmapByteSize(bitmap)
    }

    override fun toString(): String {
        return "SizeStrategy: $groupMap SortedSizes:${sortedSizes}"
    }

    private fun decrementBitmapOfSize(size: Int) {
        sortedSizes[size]?.let {
            if (it == 1) {
                sortedSizes.remove(size)
            } else {
                sortedSizes[size] = it - 1
            }
        }
    }

    class KeyPool : KBaseKeyPool<Key>() {

        fun get(size: Int): Key {
            return super.get().apply { init(size) }
        }

        override fun create(): Key {
            return (Key(this))
        }
    }

    class Key(private val pool: KeyPool) : KPoolAble {

        private var size = 0

        fun init(size: Int) {
            this.size = size
        }

        override fun offer() {
            pool.offer(this)
        }

        override fun equals(other: Any?): Boolean {
            if (this === other) return true
            if (javaClass != other?.javaClass) return false

            other as Key

            if (size != other.size) return false

            return true
        }

        override fun hashCode(): Int {
            return size
        }

        override fun toString(): String {
            return getBitmapString(size)
        }
    }

    companion object {

        const val MAX_SIZE_MULTIPLE = 8

        fun getBitmapString(size: Int): String {
            return "[${size}]"
        }

        fun getBitmapString(bitmap: Bitmap): String {
            return "[${Util.getBitmapByteSize(bitmap)}]"
        }
    }
}